﻿using System;
using System.Collections.Generic;
using System.Linq;
using Granite.Collections;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Granite.Commons.Tests.Mocks;
using System.Collections;

namespace Granite.Commons.Tests.Collections
{
    [TestClass]
    public class WeakReferenceCollectionTests
    {
        [TestMethod]
        public void WeakReferenceCollection_Add()
        {
            try
            {
                var result = new WeakReferenceCollection<string>();
                result.Add(null);

                Assert.Fail("Expected an ArgumentNullException");
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("item", ex.ParamName, "Incorrect parameter name");
            }
        }

        [TestMethod]
        public void WeakReferenceCollection_CopyTo_Test1()
        {
            try
            {
                var result = new WeakReferenceCollection<string>();
                result.CopyTo(null, 0);

                Assert.Fail("Expected an ArgumentNullException");
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("array", ex.ParamName, "Incorrect parameter name");
            }
        }

        [TestMethod]
        public void WeakReferenceCollection_CopyTo_Test2()
        {
            try
            {
                var result = new WeakReferenceCollection<string>();
                result.Add("");
                var array = new string[0];
                result.CopyTo(array, 0);

                Assert.Fail("Expected an ArgumentNullException");
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Assert.AreEqual("arrayIndex", ex.ParamName, "Incorrect parameter name");
            }
        }

        [TestMethod]
        public void WeakReferenceCollection_CopyTo_Test3()
        {
            var result = new WeakReferenceCollection<string>();
            result.Add("AAA");
            var array = new string[1];
            result.CopyTo(array, 0);
            Assert.AreEqual("AAA", array[0]);
        }

        [TestMethod]
        public void WeakReferenceCollection_CopyTo_Test4()
        {
            try
            {
                var result = new WeakReferenceCollection<string>();
                result.Add("");
                var array = new string[0];
                result.CopyTo(array, 1);

                Assert.Fail("Expected an ArgumentNullException");
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Assert.AreEqual("arrayIndex", ex.ParamName, "Incorrect parameter name");
            }
        }

        [TestMethod]
        public void WeakReferenceCollection_CopyTo_Test5()
        {
            try
            {
                var result = new WeakReferenceCollection<string>();
                result.Add("");
                var array = new string[0];
                result.CopyTo(array, -1);

                Assert.Fail("Expected an ArgumentNullException");
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Assert.AreEqual("arrayIndex", ex.ParamName, "Incorrect parameter name");
            }
        }

        [TestMethod]
        public void WeakReferenceCollection_AddRange_Test1()
        {
            try
            {
                IList<string> list = null;
                var result = new WeakReferenceCollection<string>();
                result.AddRange(list);

                Assert.Fail("Expected an ArgumentNullException");
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("list", ex.ParamName, "Incorrect parameter name");
            }
        }

        [TestMethod]
        public void WeakReferenceCollection_AddRange_Test2()
        {
            string item1 = "AAA";
            string item2 = "BBB";

            var list = new List<string>();
            list.Add(item1);
            list.Add(item2);

            var result = new WeakReferenceCollection<string>();
            result.AddRange(list);

            Assert.AreEqual("AAA", list[0]);
            Assert.AreEqual("BBB", list[1]);
        }

        [TestMethod]
        public void WeakReferenceCollection_AddRange_Test3()
        {
            string item1 = "AAA";
            string item2 = "BBB";

            var list = new List<string>();
            list.Add(item1);
            list.Add(null);
            list.Add(item2);

            var result = new WeakReferenceCollection<string>();
            try
            {
                result.AddRange(list);
                Assert.Fail("An exception was expected");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("list", ex.ParamName);
            }

        }

        [TestMethod]
        public void WeakReferenceCollection_Clear_Test1()
        {
            string item1 = "AAA";
            string item2 = "BBB";

            var list = new List<string>();
            list.Add(item1);
            list.Add(item2);

            var result = new WeakReferenceCollection<string>();
            result.AddRange(list);

            Assert.AreEqual("AAA", list[0]);
            Assert.AreEqual("BBB", list[1]);

            result.Clear();

            Assert.AreEqual(0, result.Count);
        }

        [TestMethod]
        public void WeakReferenceCollection_Remove_Test1()
        {
            string item1 = "AAA";
            string item2 = "BBB";

            var list = new List<string>();
            list.Add(item1);
            list.Add(item2);

            var result = new WeakReferenceCollection<string>();
            result.AddRange(list);

            Assert.AreEqual("AAA", list[0]);
            Assert.AreEqual("BBB", list[1]);

            Assert.IsTrue(result.Remove(item2));

            Assert.AreEqual("AAA", list[0]);
            Assert.AreEqual(1, result.Count);

            Assert.IsTrue(result.Remove(item1));

            Assert.AreEqual(0, result.Count);

            Assert.IsFalse(result.Remove(item1));
            try
            {
                result.Remove(null);
                Assert.Fail("Expected an ArgumentNullException");
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("item", ex.ParamName);
            }

        }

        [TestMethod]
        public void WeakReferenceCollection_Remove_Test2()
        {
            var result = new WeakReferenceCollection<Foo>();

            Action add = () => result.Add(new Foo());

            add();

            TestUtilities.GCCycle();

            var f = new Foo();
            result.Add(f);
            result.Add(f);
            result.Remove(f);
            result.Remove(f);
            result.CleanUp();

            Assert.AreEqual(0, result.Count);
        }

        [TestMethod]
        public void WeakReferenceCollection_GetEnumerator()
        {
            string item1 = "AAA";
            string item2 = "BBB";

            var list = new List<string>();
            list.Add(item1);
            list.Add(item2);

            var result = new WeakReferenceCollection<string>();
            result.AddRange(list);

            var e = ((IEnumerable)result).GetEnumerator();

            Assert.IsTrue(e.MoveNext());
            Assert.AreEqual("AAA", e.Current);
            Assert.IsTrue(e.MoveNext());
            Assert.AreEqual("BBB", e.Current);
            Assert.IsFalse(e.MoveNext());

            Assert.IsFalse(((ICollection<string>)result).IsReadOnly);
        }
    }
}



